package com.zhiwei.msf.common.filter;

import java.sql.Connection;
import java.util.Properties;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.stereotype.Component;

import com.zhiwei.msf.common.constant.DatabaseConstants;

/**
 * 通用Mybatis查询拦截器 <br/>
 * 1. 默认按照时间倒序
 */
@Component
@Intercepts({
        @Signature(method = "prepare", type = StatementHandler.class, args = {Connection.class, Integer.class})
})
public class MybatisQueryInterceptor implements Interceptor {

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }

    @Override
    public Object intercept(Invocation invocation) throws Exception {
        RoutingStatementHandler routingStatementHandler = (RoutingStatementHandler) invocation.getTarget();
        BoundSql boundSql = routingStatementHandler.getBoundSql();
        String originSql = boundSql.getSql();
        if (originSql.replaceAll(" ", "").contains(DatabaseConstants.ORDER_BY.replaceAll(" ", ""))) {
            return invocation.proceed();
        }

        //工具类：类似XML树形结构，可通过.的形式分离，动态赋值
        MetaObject metaObject = MetaObject.forObject(routingStatementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY,
                SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());

        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        if (SqlCommandType.SELECT.name().equals(mappedStatement.getSqlCommandType().name()) && !originSql.contains("count")) {
            metaObject.setValue("delegate.boundSql.sql", originSql + " order by " + DatabaseConstants.SQL_UPDATE_TIME + " desc");
        }
        return invocation.proceed();
    }
}
